package online.longzipeng.cinemasys.common.exception;

import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.MalformedJwtException;
import lombok.extern.slf4j.Slf4j;
import online.longzipeng.cinemasys.common.result.ResponseEnum;
import online.longzipeng.cinemasys.common.result.Result;
import org.springframework.validation.BindException;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.security.SignatureException;
import java.util.List;
import java.util.Set;

/**
 * @Author: lzp
 * @Date: 2021/2/7 19:05
 * 异常切面，统一捕获系统中的异常
 */
@ControllerAdvice
@Slf4j
public class ExceptionAop {

    /**
     * 统一处理业务异常
     */
    @ExceptionHandler(AppException.class)
    @ResponseBody
    public Result doAppException(AppException e){
        if (log.isDebugEnabled()){
            log.warn(String.format("%s,参数信息：%s",e.getMessage(),e.getData().toString()));
        }
        return new Result(e.getCode(),e.getMessage(),null);
    }

    /**
     * 捕获校验bean时产生的异常，返回通用结果集
     */
    @ExceptionHandler({BindException.class, ConstraintViolationException.class,MethodArgumentNotValidException.class})
    @ResponseBody
    public Result doBindException(Exception e){
        Result result = new Result(ResponseEnum.EXCEPTION_VALIDATOR);
        StringBuffer message = new StringBuffer(result.getMessage()+":");
        if (e instanceof BindException) {
            BindException exs = (BindException) e;
            for (ObjectError o : exs.getAllErrors()) {
                message.append(o.getDefaultMessage()).append(";");
            }
        } else if (e instanceof ConstraintViolationException) {
            ConstraintViolationException exs = (ConstraintViolationException) e;
            Set<ConstraintViolation<?>> violations = exs.getConstraintViolations();
            for (ConstraintViolation<?> item : violations) {
                message.append(item.getMessage()).append(";");
            }
        }else if (e instanceof MethodArgumentNotValidException){
            MethodArgumentNotValidException me = (MethodArgumentNotValidException) e;
            List<ObjectError> allErrors = me.getBindingResult().getAllErrors();
            allErrors.forEach(o -> message.append(o.getDefaultMessage()).append(";"));
        } else {
            log.error("捕获未处理异常，异常信息：{}", e.getMessage());
        }
        result.setMessage(message.toString());
        return result;
    }

    /*统一捕获令牌失效的三个异常*/

    /**
     * 令牌过期
     */
    @ExceptionHandler(ExpiredJwtException.class)
    @ResponseBody
    public Result doExpiredJwtException(ExpiredJwtException e){
        return new Result(ResponseEnum.TOKEN_TIMEOUT);
    }

    /**
     * token被篡改
     * @param e
     * @return
     */
    @ExceptionHandler(MalformedJwtException.class)
    @ResponseBody
    public Result doMalformedJwtException(MalformedJwtException e){
        return new Result(ResponseEnum.TOKEN_INVALID);
    }

    /**
     * 秘钥对不上
     * @param e
     * @return
     */
    @ExceptionHandler(SignatureException.class)
    @ResponseBody
    public Result doSignatureException(SignatureException e){
        return new Result(ResponseEnum.TOKEN_INVALID);
    }

    /**
     * 统一捕获参数处理错误
     * @param e
     * @return
     */
    @ExceptionHandler(IllegalArgumentException.class)
    @ResponseBody
    public Result doIllegalArgumentException(IllegalArgumentException e){
        e.printStackTrace();
        return new Result("750",e.getMessage(),null);
    }
    /**
     * 捕获其他意外产生的异常
     * @param e
     * @return
     */
    @ExceptionHandler(Exception.class)
    @ResponseBody
    public Result doException(Exception e){
        e.printStackTrace();
        if (log.isDebugEnabled()) {
            log.error(e.getMessage());
        }
        return new Result("500","未知异常",null);
    }
}
